package org.vectrics.person.privilege;

import java.util.Iterator;
import java.util.Set;
import org.apache.log4j.Logger;
import org.vectrics.SystemException;
import org.vectrics.domain.Domain;
import org.vectrics.provider.CoreServiceLocator;
import org.vectrics.user.Person;
import org.vectrics.user.UserPrivilege;
import org.vectrics.user.UserPrivilegeType;

public class PersonPrivilegeHelper {
	private transient Logger log = Logger.getLogger(this.getClass());
	private Person person = null;
	
	public PersonPrivilegeHelper(Person person) {
		super();
		this.person = person;
	}
	
    public boolean hasDomainOrGlobalRole(String neededRole, Domain domain) {
    	boolean hasRole = false;
    	if (this.person.getId().equals(CoreServiceLocator.getConfiguration().getSystemPerson().getId())) {
    		hasRole = true;
    	} else {
	    	if (log.isDebugEnabled()) 
	    		log.debug("hasRolePrivilege() called - neededRole = " + neededRole);
			
	    	UserPrivilege foundRole = this.findPrivilege(neededRole, domain);
			if ((foundRole != null) && (foundRole.getPrivilegeType().getCompanyRole())) {
				hasRole = true;
			}
	    	
	    	Domain parentDomain = domain.getParent();
			while ((hasRole == false) && (parentDomain != null)) {
		    	foundRole = this.findPrivilege(neededRole, parentDomain);
				if (foundRole == null) {
					parentDomain = parentDomain.getParent();
				} else {
					if (foundRole.getGlobal()) {
						hasRole = true;
					} else {
						log.debug("End search, found role on parent domain that doesn't propagate to children");
						parentDomain = null;
					}
				}
			}
    	}
		return(hasRole);
    }
    
	public UserPrivilege findRole(UserPrivilegeType userPrivilegeType, Domain domain) {
    	log.debug("findRole() called, userPrivilegeType = " + userPrivilegeType.getCode()
    			+ "  Domain=" + domain);
		UserPrivilege found = null;
		log.debug("findRole() called - getting role collection");
		Set roles = person.getPrivileges();
		
		if (roles == null) {
			try {
				throw new Exception("hasRole() called, but roles were never populated");
			} catch (Exception ex) { 
				log.error("hasRole() called, but roles were never populated", ex);
			}
		}
		if (roles != null) {
			if (log.isDebugEnabled()) {
				log.debug("findRole() - number of roles = " + roles.size());
			}
			Iterator iter = roles.iterator();
			while ((iter.hasNext()) && (found == null)) {
				UserPrivilege userPrivilege = (UserPrivilege)iter.next();
				String roleStr = userPrivilege.getPrivilegeType().getCode();
				if (roleStr.equals(userPrivilegeType.getCode())) {
					if (((domain == null) && (userPrivilege.getDomain() == null)) 
							|| ((domain != null) && (userPrivilege.getDomain() != null) 
									&& (userPrivilege.getDomain().getId().equals(domain.getId())))) {
						log.debug("findRole() - found needed role: " + userPrivilegeType.getCode()); 
						found = userPrivilege;
					} else {
						log.debug("findRole() - dateOwner mismatch, cur role=" + roleStr
								+ "  cur domain=" + userPrivilege.getDomain());
					}
				}
				else {
					log.debug("findRole() - role doesnt match, cur role = " + userPrivilege.getPrivilegeType().getCode()
							+ "  Cur Domain=" + userPrivilege.getDomain() 
							+ "   needed role: " + userPrivilegeType.getCode());
				}
 			}
		} else {
			log.info("roles are null");
		}
		return(found);
	}
	
	public UserPrivilege findPrivilege(String roleCode, Domain domain) {
		UserPrivilegeType userPrivilegeType = CoreServiceLocator.getPersonService().findUserPrivilegeType(roleCode);
		if (userPrivilegeType == null) 
			throw new SystemException("Could not find user role type: " + roleCode);
		return(this.findRole(userPrivilegeType, domain));
	}
	
	public void addRole(String userPrivilegeTypeCode, Domain domain, boolean global) {
		UserPrivilegeType userPrivilegeType = CoreServiceLocator.getPersonService().findUserPrivilegeType(userPrivilegeTypeCode);
		this.addRole(userPrivilegeType, domain, global);
	}
	
	public void addRole(UserPrivilegeType userPrivilegeType, Domain domain, boolean global) {
		if (log.isDebugEnabled()) {
			String doStr = "null";
			if (domain != null)
				doStr = domain.getDescription();
			log.debug("addRole() called" 
					+ "\r\n - userPrivilegeType=" + userPrivilegeType.getCode()
					+ "\r\n - company=" + doStr
				);
		}
		
		if (domain != null) {
			if (userPrivilegeType.getCode().equals(UserPrivilegeType.GLOBAL_DATAOWNER_ACCESS) == false) {
				if (this.hasDomainOrGlobalRole(UserPrivilegeType.GLOBAL_DATAOWNER_ACCESS, domain) == false) {
					this.addRole(UserPrivilegeType.GLOBAL_DATAOWNER_ACCESS, domain, global);
				}
			}
		} else {
			throw new SystemException("addRole() - was passed a null domain");
		}
		
		UserPrivilege userPrivilege = person.findPrivilege(userPrivilegeType, domain);
		if (userPrivilege != null) {
			userPrivilege.setGlobal(global);
			
		} else {
			log.debug("Person does not have role, adding...");
			userPrivilege = new UserPrivilege();
			userPrivilege.setPrivilegeType(userPrivilegeType);
			userPrivilege.setPerson(this.person);
			userPrivilege.setDomain(domain);
			userPrivilege.setGlobal(global);
			person.getPrivileges().add(userPrivilege);
		} 
	}
	
	public boolean hasRole(String userPrivilegeTypeCode, Domain domain) {
		
		UserPrivilegeType privType = CoreServiceLocator.getPersonService().findUserPrivilegeType(userPrivilegeTypeCode);
		if (privType == null)
			throw new SystemException("Could not find role type: " + userPrivilegeTypeCode);
		return(this.hasPrivilege(privType, domain));
	}
	
	public boolean hasPrivilege(UserPrivilegeType userPrivilegeType, Domain domain) {
		return(this.findRole(userPrivilegeType, domain) != null);
	}
	
}
